# coding:utf-8

'''
功能:
  自动获取窗口的位置和矩形尺寸, 监听用户的鼠标点击操作, 每点击一次, 自动截取指定位置的图片并保存

第3方模块:
  (1) pywin32(win32api接口)
      --> Anaconda自带
  (2) pyautogui(图形自动化操作)
      --> pip install pyautogui
  (3) pynput(监听鼠标、键盘消息)
      --> 从 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载whl文件
      --> 然后 pip install pynput-1.6.8-py2.py3-none-any.whl
'''
import os
import shutil
import time
# 多线程模块
import threading
from queue import Queue
# pynput模块(监听鼠标和键盘消息)
from pynput import mouse, keyboard

from util import MinimizeConsole, FixWindowRectProblem, GetChildWndRect, ReadJsonFile
from auto import AutoGuiWork

# 全局消息队列
# 数据格式: (state, x,y)
# state  -- 状态标记: 0-退出, 1-正常
# x, y   -- 坐标
msg_queue = Queue()

# 记录鼠标点击的坐标
mouse_click_points = []

def on_release(key):
  if key == keyboard.Key.esc:
    # 停止监听
    print('按下', key, '通知worker退出')
    msg_queue.put((0, None, None))
  return True

def on_click(x, y, button, pressed):
  # print('{0} at {1}'.format('Pressed' if pressed else 'Released',(x, y)), button.name, button.value)
  # 鼠标左键点击消息
  if button == mouse.Button.left and pressed:
    msg_queue.put((1, x, y))
  return True

# 启动键盘监控线程
def start_listen_keyboard():
  # 阻塞方式启动线程
  # with keyboard.Listener(on_press=None, on_release=on_release) as listener:
  #   listener.join()
  # 非阻塞方式启动线程
  listener = keyboard.Listener(on_press=None, on_release=on_release)
  listener.start()
  return listener

# 启动鼠标监控线程
def start_listen_mouse():
  # 阻塞方式启动线程
  # with mouse.Listener(on_move=on_move, on_click=on_click) as listener:
  #   listener.join()
  listener = mouse.Listener(on_move=None, on_click=on_click)
  listener.start()
  return listener

# 最底层工作
def underline_work(data):
  mouse_click_points.append(data)
  print('记录鼠标点击的坐标:', data)

# 工作线程函数
def woker(keyboard_thread, mouse_thread):
  while True:
    # 延迟0.5s
    time.sleep(1)
    if not msg_queue.empty():
      state, x, y = msg_queue.get()
      if state == 0:
        print('worker收到退出消息')
        print('worker强行终止键盘监听线程!')
        keyboard_thread.stop()
        print('worker强行终止鼠标监听线程!')
        mouse_thread.stop()
        break
      elif x != None and y != None:
        # 执行最底层工作
        underline_work((x, y))
        # msg_queue.task_done()
        
# 监听用户的鼠标、键盘操作, 点击鼠标, 记录点击位置
# 按ESC退出不再监听
# 使用多线程技术实现
def MonitorUserClickPoints():
  # 启动键盘监控线程(非阻塞)
  t1 = start_listen_keyboard()
  # 启动鼠标监控线程(非阻塞)
  t2 = start_listen_mouse()
  # 启动工作线程
  t3 = threading.Thread(target=woker, args=(t1, t2, ))
  t3.setDaemon(True)
  t3.start()
  # 阻塞主线程,等待t3执行完毕
  t3.join()
  return mouse_click_points

# 主函数
def main(config):
  # 删除并新建输出文件夹
  # shutil.rmtree(config['image_dir'], ignore_errors=True)    #递归删除文件夹
  if not os.path.exists(config['image_dir']):
    # os.rmdir(config['image_dir'])
    os.mkdir(config['image_dir'])
  # 修复win10系统下GetWindowRect()不准确的问题
  FixWindowRectProblem()
  # 最小化控制台窗口
  MinimizeConsole()
  # 获取子窗口矩形
  size = GetChildWndRect(config['mainWndClassName'], config['mainWndTitle'], config['childWndClassName'])
  # 监听用户的鼠标、键盘操作, 记录点击的坐标
  mouse_click_points = MonitorUserClickPoints()
  print('worker线程执行完毕')
  # 执行自动化操作: 点选巷道、截取图片、删除巷道
  AutoGuiWork(mouse_click_points, size, config['image_dir'])
  print('自动化截图操作执行完毕')

if __name__ == '__main__':
  # 配置参数
  config = ReadJsonFile('grab_config.json')
  main(config)